// Package dao
// @Author zhongxc
// @Date 2024/7/9 15:35:00
// @Desc
package dao

import (
	"context"
	"errors"
	"fmt"
	"gorm.io/gorm"
	"vben-admin/pkg/dao/internal"
	"vben-admin/pkg/model"
	"vben-common/msdb"
	"vben-common/msdb/gorms"
)

type MenuDao struct {
	conn    *gorms.GormConn
	columns *internal.MenuColumns
}

func NewMenuDao(db *msdb.MsDB) *MenuDao {
	return &MenuDao{
		conn:    gorms.New(db.Conn),
		columns: internal.NewMenuColumns(),
	}
}

func (d *MenuDao) GetMenuByName(ctx context.Context, name string) (*model.MenuModel, error) {
	db := d.conn.Session(ctx)
	var menuModel *model.MenuModel
	nameField := fmt.Sprintf("%s = ?", d.columns.Name)
	err := db.Where(nameField, name).First(&menuModel).Error
	if err != nil {
		if errors.Is(err, gorm.ErrRecordNotFound) {
			return nil, nil
		} else {
			return nil, err
		}
	}
	return menuModel, nil
}

func (d *MenuDao) DeleteByIds(ctx context.Context, ids []int64) error {
	db := d.conn.Session(ctx)
	idField := fmt.Sprintf("%s IN (?)", d.columns.Id)
	err := db.Where(idField, ids).Delete(&model.MenuModel{}).Error
	return err
}

func (d *MenuDao) GetMenuById(ctx context.Context, id int64) (*model.MenuModel, error) {
	db := d.conn.Session(ctx)
	var menuModel *model.MenuModel
	idField := fmt.Sprintf("%s=?", d.columns.Id)
	err := db.Where(idField, id).First(&menuModel).Error
	if err != nil {
		if errors.Is(err, gorm.ErrRecordNotFound) {
			return nil, nil
		} else {
			return nil, err
		}
	}
	return menuModel, nil
}

func (d *MenuDao) GetMenuList(ctx context.Context, name string, status int32) ([]*model.MenuModel, error) {
	db := d.conn.Session(ctx)
	var menuList []*model.MenuModel
	if name != "" {
		nameField := fmt.Sprintf("%s like ?", d.columns.Name)
		db.Where(nameField, "%"+name+"%")
	}
	statusField := fmt.Sprintf("%s = ?", d.columns.Status)
	err := db.Where(statusField, status).Where("deleted=?", 0).Find(&menuList).Error
	return menuList, err
}

func (d *MenuDao) SelectMenu(ctx context.Context) ([]*model.MenuModel, error) {
	db := d.conn.Session(ctx)
	var menuList []*model.MenuModel
	err := db.Where("type IN(?)", []int64{0, 1}).
		Where("status=?", 1).
		Where("deleted=?", 0).Find(&menuList).Error
	return menuList, err
}

func (d *MenuDao) UpdateById(ctx context.Context, id int64, menu map[string]interface{}) error {
	db := d.conn.Session(ctx)
	idField := fmt.Sprintf("%s=?", d.columns.Id)
	err := db.WithContext(ctx).Model(&model.MenuModel{}).Where(idField, id).Updates(menu).Error
	return err
}

func (d *MenuDao) CreateMenu(ctx context.Context, menu *model.MenuModel) error {
	db := d.conn.Session(ctx)
	err := db.Omit(model.IgnoreDeletedAt, model.IgnoreUpdatedAt, model.IgnoreUpdatedBy).Create(menu).Error
	return err
}

func (d *MenuDao) SelectMenuByUserId(ctx context.Context, userId int64) ([]int64, error) {
	db := d.conn.Session(ctx)

	var menuIdList []int64
	err := db.Select("DISTINCT rm.menu_id").
		Table("sys_user AS us").
		Joins("LEFT JOIN sys_role_menu AS rm ON us.role_id=rm.role_id").
		Joins("LEFT JOIN sys_menu AS m ON rm.menu_id=m.id").
		Where("us.id=?", userId).
		Where("m.deleted=?", 0).
		Where("m.status=?", 1).
		Where("m.type IN(?)", []int64{0, 1}).
		Order("rm.menu_id").
		Find(&menuIdList).Error

	return menuIdList, err
}

func (d *MenuDao) FindByParentId(ctx context.Context, parentId int64) ([]*model.MenuModel, error) {
	db := d.conn.Session(ctx)
	var menuList []*model.MenuModel
	err := db.Where("parent_id=?", parentId).Find(&menuList).Error
	return menuList, err
}
